class: inverse,left, middle background-image: url(data:image/png;base64,#background.png) background-size: cover <img src="data:image/png;base64,#LOGO_DIPLOMADO.png" width="500px"/> ##Módulo 3: Percepción remota, análisis masivo y GEE ###Google Earth Engine: Aplicaciones en GEE José A. Lastra<br> <a href="http://github.com/JoseLastra"> Github: JoseLastra</a><br> <a href="mailto:jose.lastra@pucv.cl"> jose.lastra@pucv.cl</a><br> .large[<b><a href="https://www.pucv.cl/uuaa/site/edic/base/port/labgrs.html">LabGRS</a> | Noviembre | Diciembre 2023</b>] <br> --- class: center,middle background-image: url(data:image/png;base64,#labgrs_logo.png) background-size: 35% --- ## Contenidos .pull-left[ - Trabajo con colecciones: * Importación de colecciones * Filtros temporales y espaciales * Creación de imágenes * Exportación de datos - Funciones en GEE * Uso de **map()** - Reducciones * Temporales * Espaciales - Extracción de series de tiempo ] .pull-right[ <img src="data:image/png;base64,#https://earthengine.google.com/static/images/earth-engine-logo.png" width="300px"/> ] --- ## Colecciones -- - Dentro de GEE disponemos de una gran cantidad de información, que está agrupada en colecciones. - Cada colección corresponde a un producto diferente, ya sea satelital, modelo climático, etc. - Para llamar colecciones, vamos a considerar una estructura mínima similar a lo siguiente: ```js var imageCollection = ee.ImageCollection('NOMBRE/PRODUCTO') ``` <script> var imageCollection = ee.ImageCollection('NOMBRE/PRODUCTO') </script> <center><img src="data:image/png;base64,#datasets.png" width="500px"/></center> --- ## Carga de colección Landsat 8 -- - Carguemos la colección 2 de Landsat 8 en nivel 1 ```js //Carga colección Landsat 8 (en bruto) var imageCollection = ee.ImageCollection("LANDSAT/LC08/C02/T1") ``` <script> //Carga colección Landsat 8 (en bruto) var imageCollection = ee.ImageCollection("LANDSAT/LC08/C02/T1") </script> -- - La colección completa considera la información disponible para todo el catálogo (abril 2013) hasta la actualidad. -- - La declaracion **var xx = ee.Something** es simil a la creación o asignación de un objeto en R. -- - Si imprimimos los resultados en consola usando `print(imageCollection,'colección landsat')` obtendremos el siguiente error: <center><img src="data:image/png;base64,#img1.png" width="400px"/></center> --- ## Filtros sobre una colección -- - Para poder visualizar solo la información que nos interesa o filtrar en base a criterios específicos (región de interés ,fechas, cobertura nubosa, etc.) -- - GEE dispone de varias formas que podemos emplear como: **filter()**, **filterBounds()**, **filterDate()**, etc. - Filtrar la información, nos permitirá poder imprimir en la consola los resultados e inspeccionarlos de forma más simple. -- - Utilice una geometría básica, dibujada en el mapa y aplique la función `filterBounds(nombre_geometria)` ```js //Carga colección Landsat 8 (en bruto) var imageCollection = ee.ImageCollection("LANDSAT/LC08/C02/T1") //filtro por geometría .filterBounds(geometry); print(imageCollection,'colección landsat'); ``` <script> //Carga colección Landsat 8 (en bruto) var imageCollection = ee.ImageCollection("LANDSAT/LC08/C02/T1") //filtro por geometría .filterBounds(geometry); print(imageCollection,'colección landsat'); </script> --- -- - Para este filtro el resultado debe tener un total de 907 elementos. -- - Esto variará según la zona escogida por cada uno y la fecha de consulta <center><img src="data:image/png;base64,#img2.png" width="400px"/></center> - Ahora, apliquemos un filtro de fechas considerando el año 2021 (ene - dic) ```js var imageCollection = ee.ImageCollection("LANDSAT/LC08/C02/T1") //filtro por geometría .filterBounds(geometry) //filtro de fecha .filterDate('2021-01-01', '2021-12-31'); print(imageCollection,'colección landsat'); ``` <script> var imageCollection = ee.ImageCollection("LANDSAT/LC08/C02/T1") //filtro por geometría .filterBounds(geometry) //filtro de fecha .filterDate('2021-01-01', '2021-12-31'); print(imageCollection,'colección landsat'); </script> <center><img src="data:image/png;base64,#img3.png" width="400px"/></center> --- -- - También podemos aplicar otros tipos de filtros como generales empleando `filter()`, `ee.Filter()` y los metadatos o propiedades de las imágenes ```js var imageCollection = ee.ImageCollection("LANDSAT/LC08/C02/T1") //filtro por geometría .filterBounds(geometry) //filtro de fecha .filterDate('2021-01-01', '2021-12-31') // filtro por nubosidad en tierra .filter(ee.Filter.lt('CLOUD_COVER_LAND',50)); ``` <script> var imageCollection = ee.ImageCollection("LANDSAT/LC08/C02/T1") //filtro por geometría .filterBounds(geometry) //filtro de fecha .filterDate('2021-01-01', '2021-12-31') // filtro por nubosidad en tierra .filter(ee.Filter.lt('CLOUD_COVER_LAND',50)); </script> <center><img src="data:image/png;base64,#img3.png" width="450px"/></center> --- ```js var imageCollection = ee.ImageCollection("LANDSAT/LC08/C02/T1") //filtro por geometría .filterBounds(geometry) //filtro de fecha .filterDate('2021-01-01', '2021-12-31') // Filtro por path y row .filter(ee.Filter.or( ee.Filter.and(ee.Filter.eq('WRS_PATH', 233), ee.Filter.eq('WRS_ROW', 83)))); ``` <script> var imageCollection = ee.ImageCollection("LANDSAT/LC08/C02/T1") //filtro por geometría .filterBounds(geometry) //filtro de fecha .filterDate('2021-01-01', '2021-12-31') // Filtro por path y row .filter(ee.Filter.or( ee.Filter.and(ee.Filter.eq('WRS_PATH', 233), ee.Filter.eq('WRS_ROW', 83)))); </script> <center><img src="data:image/png;base64,#img4.png" width="450px"/></center> -- - Nosotros solo filtraremos por nubosidad en tierra (**CLOUD_COVER_LAND < 50%**) y ordenaremos las imágenes usando la función **sort()** --- ```js //Carga colección Landsat 8 (en bruto) var imageCollection = ee.ImageCollection("LANDSAT/LC08/C02/T1") //filtro por geometría .filterBounds(geometry) //filtro de fecha .filterDate('2021-01-01', '2021-12-31') // filtro por nubosidad en tierra .filter(ee.Filter.lt('CLOUD_COVER_LAND',50)) // Ordenar por cobertura nubosa, ascendente. .sort('CLOUD_COVER_LAND'); ``` <script> //Carga colección Landsat 8 (en bruto) var imageCollection = ee.ImageCollection("LANDSAT/LC08/C02/T1") //filtro por geometría .filterBounds(geometry) //filtro de fecha .filterDate('2021-01-01', '2021-12-31') // filtro por nubosidad en tierra .filter(ee.Filter.lt('CLOUD_COVER_LAND',50)) // Ordenar por cobertura nubosa, ascendente. .sort('CLOUD_COVER_LAND'); </script> <center><img src="data:image/png;base64,#img5.png" width="450px"/></center> -- - La fecha de las imágenes menos nubosas con estos filtros es: **2021-04-09** --- ## Creación de imagen -- - Cada colección dispone de diferentes archivos dentro de ella, desde rasters individuales hasta archivos multibanda. - Podemos crear una imagen empleando uno de los archivos dentro de la colección o podemos crear reducciones de toda la colección (cosa que veremos más adelante) - **Importante:** Debemos tener en cuenta como se almacena la información y los nombres de las capas de información para seleccionar. - La estructura base es la siguiente: ```js var image = ee.Image('LANDSAT/LC08/C02/T1/LC08_001082_20210409') ``` <script> var image = ee.Image('LANDSAT/LC08/C02/T1/LC08_001082_20210409') </script> -- - Debemos considerar la información del id de la imagen incluyendo toda la ruta al dataset. --- ## Creación de imagen -- - También, podemos usar una colección de imágenes filtrada como la generada anteriormente y seleccionar los datos internamente - Esto nos permite aplicar filtros adicionales y seleccionar solo cierta información. ```js //Imagen menos nubosa para el periodo var image = ee.Image((imageCollection) //Selección de bandas ópticas .select(['B[1-7]']) //selección de imagen menos nubosa .first()); print(image, 'L8 menos nubosa'); ``` <script> //Imagen menos nubosa para el periodo var image = ee.Image((imageCollection) //Selección de bandas ópticas .select(['B[1-7]']) //selección de imagen menos nubosa .first()); print(image, 'L8 menos nubosa'); </script> <center><img src="data:image/png;base64,#img6.png" width="450px"/></center> --- ## Visualizando datos -- - La función que nos permite agregar información al mapa es **Map.addLayer()** - Donde podemos agregar una colección de imágenes, una imagen, vecrtores, etc. ```js //Agregando imagen a la visualización Map.addLayer(image,{}, 'L8 Image sin parámetros de visualización'); //Mejorando la visualización Map.addLayer(image, {bands: ['B4', 'B3', 'B2'], min:2000, max: 9000,gamma: 0.25}, 'Mejor L8'); ``` <script> //Agregando imagen a la visualización Map.addLayer(image,{}, 'L8 Image sin parámetros de visualización'); //Mejorando la visualización Map.addLayer(image, {bands: ['B4', 'B3', 'B2'], min:2000, max: 9000,gamma: 0.25}, 'Mejor L8'); </script> --- class: center,middle background-image: url(data:image/png;base64,#comparison.png) background-size: 80% --- ## Exportación de datos ráster -- - Al procesar la información dentro de GEE, podemos optimizar el uso de espacio y descargar solo los resultados o solo la imagen acotada a una zona de nuestro interés. - Para exportar podemos hacerlo a un asset (dentro de GEE), Google Cloud o Google Drive. - En el caso de Google Cloud debemos considerar pago por uso de almacenamiento. - En el caso de Google Drive y assets estamos limitados al espacio de cada plataforma. * Para los **assets** 250 GB ó 10.000 archivos * Google Drive, depende del nivel de usuario. -- - **Consideraciones al exportar**: * Los datos exportados deben tener el mismo datatype * Las funciones de exportación esperan una imagen como entrada, **No una colección de imágenes**. * *maxPixels* permite controlar el número de pixeles a exportar, por defecto ***1e8 (100.000.000 px.)*** * Cuando se alcanza el límite de exportación, GEE divide nuestro archivo. --- ## Exportando a Google Drive -- - Dibuje una región de interés (**ROI**) dentro del área de imágenes disponibles y úsela como región para exportar ```js //Exportar datos // Google Drive Export // (nota: requiere que el usuario oprima 'Run') Export.image.toDrive({ image: image, //imagen a descargar description: 'image_example_drive', // scale: 30,//tamaño de salida del pixel region: roi, // región de interés para exportación crs: 'EPSG:4326',// sistema de referencia del archivo 4326 equivale a LatLong WGS 84 maxPixels: 2000000000 //número de pixeles para exportación }); ``` <script> //Exportar datos // Google Drive Export // (nota: requiere que el usuario oprima 'Run') Export.image.toDrive({ image: image, //imagen a descargar description: 'image_example_drive', // scale: 30,//tamaño de salida del pixel region: roi, // región de interés para exportación crs: 'EPSG:4326',// sistema de referencia del archivo 4326 equivale a LatLong WGS 84 maxPixels: 2000000000 //número de pixeles para exportación }); </script> --- ## Exportando al Asset ```js // Asset Folder Export // (nota: requiere que el usuario oprima 'Run') Export.image.toAsset({ image: image, description: 'image_example_asset', assetId: 'users/joselastra/image_example',//reemplazar con su nombre de usuario scale: 30, region: roi, pyramidingPolicy: {'.default':'mean'}, // usar {'.default':'sample'} para datos discretos o 'mode' maxPixels: 2000000000 }); ``` <script> // Asset Folder Export // (nota: requiere que el usuario oprima 'Run') Export.image.toAsset({ image: image, description: 'image_example_asset', assetId: 'users/joselastra/image_example',//reemplazar con su nombre de usuario scale: 30, region: roi, pyramidingPolicy: {'.default':'mean'}, // usar {'.default':'sample'} para datos discretos o 'mode' maxPixels: 2000000000 }); </script> --- ## Exportación de datos ráster -- - Para todas las exportaciones, se requiere que el usuario active el **task** para ser enviado al servidor. <center><img src="data:image/png;base64,#img7.png" width="450px"/></center> -- - Si queremos cancelar uno o varios task, podemos hacerlo directamente o ir al [**Task Manager**](https://code.earthengine.google.com/tasks) <center><img src="data:image/png;base64,#img8.png" width="550px"/></center> --- ## Creación y aplicación de funciones -- - **Funciones**: Dentro de la sección **Docs** de GEE, tiene a disposición funciones específicas para trabajar con imágenes y con colecciones de imágenes, dependiendo de cuál sea el análisis a realizar: funciones booleanas, matemáticas, transformaciones, análisis espectral, entre otros. -- - Para aplicar masivamente un análisis, normalmente se recurre al uso de ciclos. -- - **Importante:** En nuestro code editor se recomienda evitar a toda costa el uso convencional de ciclos; debido a que esto trae la operación al explorador y puede generar errores de funcionamiento. --- ## Uso de map() -- - En GEE se dispone de la función **map()** para lograr el procesamiento masivo de datos (colecciones de imágenes, geometrías, etc.) -- - La función **map()** envía automáticamente la operación a los servidores de Google para ser paralelizado permitiendo tener resultados en segundos. -- - Usaremos el producto Sentinel 2 (MSI) de nivel 2 y filtraremos una zona de interés considerando todas las imágenes disponibles. -- - **Importante:** recuerde que puede agregar más filtros: nubosidad, calidad de la imagen, etc. --- ## Uso de map() y funciones propias -- - Carga de datos y filtro de la colección ```js /* Funciones propias aplicadas a colecciones de datos satelitales*/ //Carga colección Sentinel 2 (SR) var s2 = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED") .filterBounds(geometry) .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',50)); print(s2,'colección Sentinel'); ``` <script> /* Funciones propias aplicadas a colecciones de datos satelitales*/ //Carga colección Sentinel 2 (SR) var s2 = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED") .filterBounds(geometry) .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',50)); print(s2,'colección Sentinel'); </script> <center><img src="data:image/png;base64,#img9.png" width="550px"/></center> --- ## Uso de map() y funciones propias -- - A continuación, crearemos una función simple para enmascarar nubes empleando la banda **QA60** disponible en el producto. ```js /* * función para enmascarado de nubes * @param {ee.Image} image imagen Sentinel-2 * @return {ee.Image} imagen Sentinel-2 enmascarada */ var maskS2clouds =function(image) { var qa = image.select('QA60'); // Bits 10 y 11: nubes y cirrus var cloudBitMask = 1 << 10; var cirrusBitMask = 1 << 11; // Ambos valores deben ser setados a 0 para indicar condiciones limpias var mask = qa.bitwiseAnd(cloudBitMask).eq(0) .and(qa.bitwiseAnd(cirrusBitMask).eq(0)); return image.updateMask(mask).divide(10000) .copyProperties(image, image.propertyNames()); //aplicación máscara } ``` <script> /* * función para enmascarado de nubes * @param {ee.Image} image imagen Sentinel-2 * @return {ee.Image} imagen Sentinel-2 enmascarada */ var maskS2clouds =function(image) { var qa = image.select('QA60'); // Bits 10 y 11: nubes y cirrus var cloudBitMask = 1 << 10; var cirrusBitMask = 1 << 11; // Ambos valores deben ser setados a 0 para indicar condiciones limpias var mask = qa.bitwiseAnd(cloudBitMask).eq(0) .and(qa.bitwiseAnd(cirrusBitMask).eq(0)); return image.updateMask(mask).divide(10000) .copyProperties(image, image.propertyNames()); //aplicación máscara } </script> .footnote[Ejemplo adaptado desde: [Harmonized Sentinel-2 MSI: MultiSpectral Instrument, Level-2A](https://developers.google.com/earth-engine/datasets/catalog/COPERNICUS_S2_SR_HARMONIZED#description)] --- ## Aplicando la función -- - Con la función construída, la aplicaremos a cada elemento en la colección. ```js // Aplicación con map var s2_clean = s2.map(maskS2clouds); ``` <script> // Aplicación con map var s2_clean = s2.map(maskS2clouds); </script> -- - Visualicemos los resultados ```js // Parámetros de visualización var VisParams = { min: 0.0, max: 0.3, bands: ['B4', 'B3', 'B2'], }; //centrar mapa Map.setCenter(-70.7, -33.3, 12); // Agregar a visualización Map.addLayer(s2.sort('system:time_start', true).first(), VisParams, 'RGB raw'); Map.addLayer(s2_clean.sort('system:time_start', true).first(), VisParams, 'RGB clean'); ``` <script> // Parámetros de visualización var VisParams = { min: 0.0, max: 0.3, bands: ['B4', 'B3', 'B2'], }; //centrar mapa Map.setCenter(-70.7, -33.3, 12); // Agregar a visualización Map.addLayer(s2.sort('system:time_start', true).first(), VisParams, 'RGB raw'); Map.addLayer(s2_clean.sort('system:time_start', true).first(), VisParams, 'RGB clean'); </script> --- class: center,middle background-image: url(data:image/png;base64,#img10.png) background-size: 80% --- ## Consideraciones -- - Podemos mejorar la función empleando alguna de las bandas auxiliares: * **SCL** * **MSK_CLDPRB** ```js var maskCloudSR = function(image) { var cloudProb = image.select('MSK_CLDPRB'); //selección prob nubes var cloud = cloudProb.lt(50); //50% var scl = image.select('SCL');// selección mapa de clasificación var shadow = scl.eq(3); // 3 = cloud shadow var cirrus = scl.eq(10); // 10 = cirrus // Probabilidad menor al 50% o sombre de nube y cirrus var mask = cloud.and(cirrus.neq(1)).and(shadow.neq(1)); return image.addBands(image.updateMask(mask).divide(10000),null, true); } // Aplicación con map var s2_clean = s2.map(maskCloudSR); ``` <script> var maskCloudSR = function(image) { var cloudProb = image.select('MSK_CLDPRB'); //selección prob nubes var cloud = cloudProb.lt(50); //50% var scl = image.select('SCL');// selección mapa de clasificación var shadow = scl.eq(3); // 3 = cloud shadow var cirrus = scl.eq(10); // 10 = cirrus // Probabilidad menor al 50% o sombre de nube y cirrus var mask = cloud.and(cirrus.neq(1)).and(shadow.neq(1)); return image.addBands(image.updateMask(mask).divide(10000),null, true); } // Aplicación con map var s2_clean = s2.map(maskCloudSR); </script> -- - Compare resultados --- ## Aplicando varias funciones - Dentro de nuestro código, podemos emplear una sola función que ejecute todos los análisis y procesamientos que requerimos y aplicarlos de una sola vez. - Desventaja: si algo falla en el código es más difícil de encontrar. - Por esta razón, lo recomendable es modularizar los procesos y ponerlos en funciones diferentes. - A continuación, crearemos una función para cortar la imagen a un área de interés. Empleando un ROI creado a partir de las herramientas de geometría. - Crear función de corte ```js //función para cortar imágenes al área de estudio var crop = function (image){ var crop1 = image.clip(ROI); return image.addBands(crop1, null, true); }; ``` <script> //función para cortar imágenes al área de estudio var crop = function (image){ var crop1 = image.clip(ROI); return image.addBands(crop1, null, true); }; </script> --- ## Aplicando varias funciones .pull-left[ <center><img src="data:image/png;base64,#img11.png" width="400px"/></center> ] .pull-right[ ```js var s2_clean = s2.map(maskCloudSR).map(crop); ``` <script> var s2_clean = s2.map(maskCloudSR).map(crop); </script> <center><img src="data:image/png;base64,#img12.png" width="400px"/></center> ] --- ## Agregando información a nuestra colección -- - Además de la información que viene por defecto en el producto, el usuario puede crear nueva información a partir de una función de cálculo (ej. NDVI, EVI, temperatura, etc.) y agregarla a dentro de la colección. -- - Realizaremos el cálculo del Índice de vegetación de diferencia normalizada (NDVI, en inglés), empleando la información de nuestra colección de nombre **s2_clean**. -- - **Importante:** podemos generar una función empleando operadores matemáticos simples o a partir de funciones disponibles dentro de GEE. El resultado es el mismo. ```js // Crear función para cálculo de NDVI versión simple var NDVI = function(img){ var index = img.normalizedDifference(['B5','B4']).rename('NDVI'); return img.addBands(index, null, true); }; // Crear función para cálculo de NDVI versión con operadores matemáticos var NDVI2 = function(img){ var index = img.select('B8').subtract(img.select('B4')) .divide(img.select('B8').add(img.select('B4'))) return img.addBands(index, null, true); }; ``` <script> // Crear función para cálculo de NDVI versión simple var NDVI = function(img){ var index = img.normalizedDifference(['B5','B4']).rename('NDVI'); return img.addBands(index, null, true); }; // Crear función para cálculo de NDVI versión con operadores matemáticos var NDVI2 = function(img){ var index = img.select('B8').subtract(img.select('B4')) .divide(img.select('B8').add(img.select('B4'))) return img.addBands(index, null, true); }; </script> -- - Haremos uso de la versión 1 --- ## Cálculo NDVI ```js // aplicación NDVI var s2_NDVI = s2_clean.map(NDVI); print(s2_NDVI, 'NDVI sentinel data'); // Visualización var NDVI_params = {min:-0.1, max:1, palette: [ 'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', '74A901', '66A000', '529400', '3E8601', '207401', '056201', '004C00', '023B01', '012E01', '011D01', '011301' ], bands: 'NDVI'}; Map.addLayer(s2_NDVI.first(), NDVI_params, 'NDVI'); ``` <script> // aplicación NDVI var s2_NDVI = s2_clean.map(NDVI); print(s2_NDVI, 'NDVI sentinel data'); // Visualización var NDVI_params = {min:-0.1, max:1, palette: [ 'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', '74A901', '66A000', '529400', '3E8601', '207401', '056201', '004C00', '023B01', '012E01', '011D01', '011301' ], bands: 'NDVI'}; Map.addLayer(s2_NDVI.first(), NDVI_params, 'NDVI'); </script> --- <center><img src="data:image/png;base64,#img13.png" width="650px"/></center> <center><img src="data:image/png;base64,#img14.png" width="550px"/></center> --- ## Reducciones o agregaciones temporales - Las reducciones (**reducers**) se utilizan para agregar información dentro de una colección a nivel **temporal y/o espacial**. - Estas agregaciones pueden ser de diferentes estadísticas y tipos, disponiendo de elementos como suma o conteo. <center><img src="data:image/png;base64,#https://developers.google.com/static/earth-engine/images/Reduce_ImageCollection.png" width="220px"/></center> .center[Fuente: [Google Developers, 2021](https://developers.google.com/earth-engine/guides/reducers_image_collection)] --- ## Reducciones o agregaciones temporales -- - Empleando nuestro set de datos de nombre **s2_NDVI** realicemos una reducción considerando solo el verano de 2021-22 (Dic-Ene-Feb) ```js // Creando reducción var s2_ver = s2_clean //colección .filterDate('2021-12-01', '2022-02-28') // selección de verano .select(['B.*', 'NDVI']) //selección de datos a reducir .reduce(ee.Reducer.mean()); // reductor ``` <script> // Creando reducción var s2_ver = s2_clean //colección .filterDate('2021-12-01', '2022-02-28') // selección de verano .select(['B.*', 'NDVI']) //selección de datos a reducir .reduce(ee.Reducer.mean()); // reductor </script> <center><img src="data:image/png;base64,#img15.png" width="450px"/></center> --- -- - Visualicemos los resultados ```js // Parámetros de visualización var NDVI_params = {min:-0.1, max:1, palette: [ 'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', '74A901', '66A000', '529400', '3E8601', '207401', '056201', '004C00', '023B01', '012E01', '011D01', '011301' ], bands: 'NDVI_mean'}; var RGB_params = { min: 0.0, max: 0.3, bands: ['B4_mean', 'B3_mean', 'B2_mean'], } // info al mapa Map.addLayer(s2_ver, NDVI_params, 'NDVI mean'); Map.addLayer(s2_ver, RGB_params, 'RGB clean',false) ``` <script> // Parámetros de visualización var NDVI_params = {min:-0.1, max:1, palette: [ 'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', '74A901', '66A000', '529400', '3E8601', '207401', '056201', '004C00', '023B01', '012E01', '011D01', '011301' ], bands: 'NDVI_mean'}; var RGB_params = { min: 0.0, max: 0.3, bands: ['B4_mean', 'B3_mean', 'B2_mean'], } // info al mapa Map.addLayer(s2_ver, NDVI_params, 'NDVI mean'); Map.addLayer(s2_ver, RGB_params, 'RGB clean',false) </script> --- class: center,middle background-image: url(data:image/png;base64,#img16.png) background-size: 80% --- ## Reducciones o agregaciones temporales -- - Además del ejemplo de reducción visto sobre la colección, también podemos obtener estadísticos zonales empleando **geometrías** o **feature collections** empleando las funciones **reduceRegion()** o **reduceRegions()** -- - Primero dibuje un polígono dentro de una zona de interés y úselo para extraer la información de sus datos de verano. ```js //Estadísticas de zona // valor promedio para polígono de interés var mean = s2_ver.reduceRegion({ geometry: zona, reducer: ee.Reducer.mean(), scale: 10 // resolución de archivos }); print(mean); ``` <script> //Estadísticas de zona // valor promedio para polígono de interés var mean = s2_ver.reduceRegion({ geometry: zona, reducer: ee.Reducer.mean(), scale: 10 // resolución de archivos }); print(mean); </script> --- class: middle <center><img src="data:image/png;base64,#img17.png" width="425px"/></center> --- ## Reducciones o agregaciones temporales -- - Para calcular las estadícticas de zona en áreas específicas, cargue en sus **Assets** el archivo de nombre **zonas.zip** - Luego lo importaremos a nuestro script y calcularemos el valor promedio para todos los polígonos en nuestro asset. <center><img src="data:image/png;base64,#img18.png" width="500px"/></center> --- class: middle .pull-left[ ```js //Para varios polígonos var means = s2_ver.reduceRegions({ collection: zonas, reducer: ee.Reducer.mean(), scale: 10 // resolución de archivos }); print(means,'means values'); ``` <script> //Para varios polígonos var means = s2_ver.reduceRegions({ collection: zonas, reducer: ee.Reducer.mean(), scale: 10 // resolución de archivos }); print(means,'means values'); </script> ] .pull-right[ <center><img src="data:image/png;base64,#img19.png" width="550px"/></center> ] --- ## Exportando información tabular -- - La información extraída a los polígonos puede ser exportada al igual que las imágenes, para ser analizada posteriormente en otro programa o plataforma. .pull-left[ ```js //descarga de datos tabulares sin geometría // Selección de columnas var salida = means.select(['N.*','B.*'], null, false); // Table to Drive Export Example Export.table.toDrive({ collection: salida, description: 'ejemplo_descarga_csv', fileFormat: 'CSV' }); ``` <script> //descarga de datos tabulares sin geometría // Selección de columnas var salida = means.select(['N.*','B.*'], null, false); // Table to Drive Export Example Export.table.toDrive({ collection: salida, description: 'ejemplo_descarga_csv', fileFormat: 'CSV' }); </script> ] .pull-right[ ```js //descarga de datos tabulares con geometría // Table to Drive Export Example Export.table.toDrive({ collection: means, description: 'ejemplo_descarga_shp', fileFormat: 'SHP' }); ``` <script> //descarga de datos tabulares con geometría // Table to Drive Export Example Export.table.toDrive({ collection: means, description: 'ejemplo_descarga_shp', fileFormat: 'SHP' }); </script> ] --- ## Bibliografía complementaria - Earth Engine Code Editor | Google Earth Engine |. (s.f.). Google Developers. https://developers.google.com/earth-engine/guides/playground - Gorelick, N., Hancher, M., Dixon, M., Ilyushchenko, S., Thau, D., & Moore, R. (2017). Google Earth Engine: Planetary-scale geospatial analysis for everyone. Remote sensing of Environment, 202, 18-27. [Ver](https://www.sciencedirect.com/science/article/pii/S0034425717302900) - Mutanga, O., & Kumar, L. (2019). Google earth engine applications. Remote Sensing, 11(5), 591. [Ver](https://www.mdpi.com/2072-4292/11/5/591/htm) - Zhao, Q., Yu, L., Li, X., Peng, D., Zhang, Y., & Gong, P. (2021). Progress and trends in the application of Google Earth and Google Earth Engine. Remote Sensing, 13(18), 3778. [Ver](https://www.mdpi.com/2072-4292/13/18/3778) --- class: inverse middle 